<?php
/**
 * IDarRelation
 * 
 * @package util.dar.relation  
 * @copyright  Copyright (c) 2006-2008 4kiki.net (http://www.4kiki.net)
 * @version    $Id: IDarRelation.php 312 2008-04-23 16:29:38Z iwind $
 */


/**
 * dar关系
 * 
 * 支持四种数据库关系:
 * - hasOne - 一对一 
 * - hasMany - 多对多
 * - belongsTo - 多对一
 * - hasMany + belongsTo + hasMany 多对多
 * 
 * belongsTo示例：
 * <pre>
 * "belongsTo" => array(
 *					"mappedBy" => "categoryId",
 *					"model" => "TCategory",
 *					"field" => "id"
 *				)
 *
 * </pre>
 * 
 * 
 * @version $Id: IDarRelation.php 312 2008-04-23 16:29:38Z iwind $
 * @package util.dar.relation
 * @since 0.0.3
 */
class IDarRelation extends IObject {
	const ONE_TO_ONE = "ONE_TO_ONE";
	const MANY_TO_ONE = "MANY_TO_ONE";
	const ONE_TO_MANY = "ONE_TO_MANY";
	const FETCH_LAZY = 1;
	const FETCH_EAGER = 2;
	
	/**
	 * 主表
	 *
	 * @var IDarModel
	 * @since 0.1
	 */
	private $main;

	/**
	 * 关联表
	 *
	 * @var IDarModel
	 * @since 0.1
	 */
	private $assoc;
	
	/**
	 * 关联类型
	 *
	 * @var integer
	 * @since 0.1
	 */
	private $type;
	
	/**
	 * 是否可选
	 *
	 * @var boolean
	 * @since 0.1
	 */
	private $isOptional = true;
	
	/**
	 * 主表字段
	 *
	 * @var IDarField
	 * @since 0.1
	 */
	private $mainField;
	
	/**
	 * 关联字段
	 *
	 * @var IDarField
	 * @since 0.1
	 */
	private $assocField;
	
	/**
	 * 获取方式
	 * 
	 * 可以是
	 * IDarRelation.FETCH_LAZY
	 * IDarRelation.FETCH_EAGER
	 *
	 * @var integer
	 * @since 0.1
	 */
	private $fetchType;
	
	/**
	 * 构造器
	 *
	 * @since 0.1
	 */
	public function __construct() {
		
	}
	
	/**
	 * 根据参数生成DAR关系
	 * 
	 *				"belongsTo" => array(
	 *					"model" => "TCategory",
	 *					"field" => "id"
	 *				)
	 * 
	 * @return IDarRelation
	 * @since 0.1
	 */
	public static function create(IDarField $field, array $config) {
		$table = $field->getTable();
		$model = $table->getModel();
		$relation = new IDarRelation();
		$relation->setMain($model);
		
		//model factory
		$factory = IDarModelFactory::getInstance();
		
		//type
		$type = array_key_exists("type", $config)?$config["type"]:null;
		
		//set type
		switch ($type) {
			case "hasOne":
				$relation->setType(IDarRelation::ONE_TO_ONE);
				break;
			case "hasMany":
				$relation->setType(IDarRelation::ONE_TO_MANY);
				break;
			case "belongsTo":
				$relation->setType(IDarRelation::MANY_TO_ONE);	
				break;
			default:
				$relation->setType(IDarRelation::ONE_TO_MANY);
		}
		
		if (array_key_exists("model", $config)) {
			$assoc = $factory->getModel($config["model"]);
			if ($assoc == null) {
				throw new IDarException("model '" . $model->getName() . "' table '" . $table->getName() . "' field '" . $field->getName() . "': relation model '{$config["model"]}' does not exist");
			}
			$relation->setAssoc($assoc);
		}
		if (array_key_exists("field", $config)) {//添加关联关系
			$assocField = $assoc->getTable()->getField($config["field"]);
//			if ($assocField->isVirtual()) {
				//throw new IDarException("model '" . $model->getName() . "' table '" . $table->getName() . "' field '" . $assocField->getName() . "': relation field '" . $assocField->getName() . "' cannot be virtual");
//			}
			$relation->setAssocField($assocField);
		}
		else {
			throw  new IDarException("relation field is not specified between '" . $model->getName() . "' AND '" . $assoc->getName() . "'");
		}
		if (array_key_exists("optional", $config)) {
			$relation->setOptional($config["optional"]);
		}
		if (array_key_exists("fetchType", $config)) {
			$relation->setFetchType($config["fetchType"]);
		}
		if (array_key_exists("mappedBy", $config)) {
			$mainField = $table->getField($config["mappedBy"]);
			$relation->setMainField($table->getField($config["mappedBy"]));
			$field->setColumn($mainField->getColumn());
		}
		else {
			throw  new IDarException("relation mappedBy is not specified between '" . $model->getName() . "' AND '" . $assoc->getName() . "'");
		}
		
		return $relation;
	}
	
	
	/**
	 * 取得主表
	 *
	 * @return IDarModel
	 * @since 0.1
	 */	
	public function getMain() {
		return $this->main;
	}
	
	/**
	 * Enter description here...
	 *
	 * @param IDarModel $main
	 * @since 0.1
	 */
	public function setMain(IDarModel $main) {
		$this->main = $main;
	}
	
	/**
	 * 取得关联的表
	 *
	 * @return IDarModel
	 * @since 0.1
	 */
	public function getAssoc() {
		return $this->assoc;
	}
	
	/**
	 * Enter description here...
	 *
	 * @param IDarModel $assoc
	 * @since 0.1
	 */
	public function setAssoc(IDarModel $assoc) {
		$this->assoc = $assoc;
	}
	
	/**
	 * 取得主表中和关联表对应的字段
	 *
	 * @return IDarField
	 * @since 0.1
	 */
	public function getMainField() {
		return $this->mainField;
	}
	
	/**
	 * Enter description here...
	 *
	 * @param IDarField $field
	 * @since 0.1
	 */
	public function setMainField(IDarField $field) {
		$this->mainField = $field;
	}
	
	/**
	 * 取得关联表中和主表对象的字段
	 *
	 * @return IDarField
	 * @since 0.1
	 */
	public function getAssocField() {
		return $this->assocField;
	}
	
	/**
	 * Enter description here...
	 *
	 * @param IDarField $field
	 * @since 0.1
	 */
	public function setAssocField(IDarField $field) {
		$this->assocField = $field;
	}
	
	/**
	 * 取得关系类型
	 *
	 * @return string
	 * @since 0.1
	 */
	public function getType() {
		return $this->type;
	}
	
	/**
	 * Enter description here...
	 *
	 * @param integer $type 关联类型
	 * @since 0.1
	 */
	public function setType($type) {
		if (!in_array($type, array(self::ONE_TO_MANY, self::ONE_TO_ONE, self::MANY_TO_ONE))) {
			throw new IDarException("unknown relation type");
		}
		$this->type = $type;
	}
	
	/**
	 * 是否可选
	 *
	 * @return boolean
	 * @since 0.1
	 */
	public function isOptional() {
		return $this->isOptional;
	}
	
	/**
	 * Enter description here...
	 *
	 * @param unknown_type $isOptional
	 * @since 0.1
	 */
	public function setOptional($isOptional) {
		$this->isOptional = $isOptional;
	}
	
	/**
	 * 数据获取方式(lazy,eager)
	 *
	 * @since 0.1
	 */
	public function setFetchType($fetchType) {
		$this->fetchType = $fetchType;
	}
	
	/**
	 * 取得数据获取方式
	 *
	 * @return integer
	 * @since 0.1
	 */
	public function getFetchType() {
		return $this->fetchType;
	}
}

?>